package com.hjy.view;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import com.hjy.myocr.OcrApplication;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.WritableImage;
import javafx.scene.input.*;
import com.benjaminwan.ocrlibrary.OcrResult;
import com.benjaminwan.ocrlibrary.Point;
import com.benjaminwan.ocrlibrary.TextBlock;
import com.hjy.util.SliderListener;
import io.github.mymonstercat.Model;
import io.github.mymonstercat.ocr.InferenceEngine;
import io.github.mymonstercat.ocr.config.ParamConfig;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Group;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;

public class View1 implements Initializable {

    //public static String imageUrl = System.getProperty("user.dir") + "/src/main/resources/images/def.jpeg";
    public static String imageUrl = "";

    public static String desktopUrl = System.getProperty("java.io.tmpdir");


    @FXML
    private ImageView imageOri;
    @FXML
    private VBox vbox;
    @FXML
    private Slider paddingSlider;
    @FXML
    private TextField paddingTextField;
    @FXML
    private Slider maxSideLenSlider;
    @FXML
    private TextField maxSideLenTextField;
    @FXML
    private Slider boxScoreThreshSlider;
    @FXML
    private TextField boxScoreTextField;
    @FXML
    private Slider boxThreshSlider;
    @FXML
    private TextField boxThreshTextField;
    @FXML
    private Slider unClipRatioSlider;
    @FXML
    private TextField unClipRatioTextField;
    @FXML
    private RadioButton doAngleRadioButton;
    @FXML
    private RadioButton mostAngleRadioButton;
    @FXML
    private Button chooseImageButton;
    @FXML
    private Button screenshotButton;
    @FXML
    private Button sbButton;
    @FXML
    private ScrollPane imageScrollPane;
    @FXML
    private TextArea outData;
    @FXML
    private Label paddingLabel;
    @FXML
    private Label maxSideLenLabel;
    @FXML
    private Label boxScoreLabel;
    @FXML
    private Label boxThreshLabel;
    @FXML
    private Label unClipRatioLabel;
    @FXML
    private Label doAngleLabel;
    @FXML
    private Label mostAngleLabel;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        try {
            //监听Slider 显示TextField
            SliderListener.extracted(paddingSlider, paddingTextField, "int");
            SliderListener.extracted(maxSideLenSlider, maxSideLenTextField, "int");
            SliderListener.extracted(boxScoreThreshSlider, boxScoreTextField, "double");
            SliderListener.extracted(boxThreshSlider, boxThreshTextField, "double");
            SliderListener.extracted(unClipRatioSlider, unClipRatioTextField, "double");

            //默认图片
            imageOri.setImage(new Image(Objects.requireNonNull(this.getClass().getResourceAsStream("/images/def.jpeg"))));
            InputStream inputStream = this.getClass().getResourceAsStream("/images/def.jpeg");
            BufferedImage image = ImageIO.read(inputStream);
            ImageIO.write(image, "png", new File(desktopUrl + "temp.png"));
            //saveToFile(inputStream, desktopUrl + "temp.png");
            imageUrl = desktopUrl + "temp.png";
            //设置图片缩放 拖动
            setImage();

            // 创建一个工具提示对象
            Tooltip tooltip = new Tooltip("快捷键：F2");
            Tooltip.install(screenshotButton, tooltip);
            Tooltip paddingTooltip = new Tooltip("图像外接白框，用于提升识别率，文字框没有正确框住所有文字时，增加此值。默认50");
            Tooltip.install(paddingLabel, paddingTooltip);
            Tooltip maxSideLenTooltip = new Tooltip("按图像长边进行总体缩放，放大增加识别耗时但精度更高，缩小减小耗时但精度降低，maxSideLen为0表示不缩放");
            Tooltip.install(maxSideLenLabel, maxSideLenTooltip);
            Tooltip boxScoreTooltip = new Tooltip("文字框置信度门限，文字框没有正确框住所有文字时，减小此值");
            Tooltip.install(boxScoreLabel, boxScoreTooltip);
            Tooltip boxThreshTooltip = new Tooltip("同上，自行试验");
            Tooltip.install(boxThreshLabel, boxThreshTooltip);
            Tooltip unClipRatioTooltip = new Tooltip("单个文字框大小倍率，越大时单个文字框越大");
            Tooltip.install(unClipRatioLabel, unClipRatioTooltip);
            Tooltip doAngleTooltip = new Tooltip("启用(true)/禁用(false) 文字方向检测，只有图片倒置的情况下(旋转90~270度的图片)，才需要启用文字方向检测，默认关闭");
            Tooltip.install(doAngleLabel, doAngleTooltip);
            Tooltip mostAngleTooltip = new Tooltip("启用(1)/禁用(0) 角度投票(整张图片以最大可能文字方向来识别)，当禁用文字方向检测时，此项也不起作用，默认关闭");
            Tooltip.install(mostAngleLabel, mostAngleTooltip);

            vbox.setOnKeyPressed(event -> {
                System.out.println(event.getCode().getName());
                if (event.getCode() == KeyCode.F2) {
                    screenshot();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void run(ActionEvent actionEvent) throws IOException {
        sbButton.setText("正在识别…");
        sbButton.setDisable(true);
        //图像外接白框，用于提升识别率，文字框没有正确框住所有文字时，增加此值。默认50。
        int padding = Integer.parseInt(paddingTextField.getText());
        //按图像长边进行总体缩放，放大增加识别耗时但精度更高，缩小减小耗时但精度降低，maxSideLen为0表示不缩放
        int maxSideLen = Integer.parseInt(maxSideLenTextField.getText());
        //文字框置信度门限，文字框没有正确框住所有文字时，减小此值
        float boxScore = Float.parseFloat(boxScoreTextField.getText());
        //同上，自行试验
        float boxThresh = Float.parseFloat(boxThreshTextField.getText());
        //单个文字框大小倍率，越大时单个文字框越大
        float unClipRatio = Float.parseFloat(unClipRatioTextField.getText());
        //启用(true)/禁用(false) 文字方向检测，只有图片倒置的情况下(旋转90~270度的图片)，才需要启用文字方向检测，默认关闭
        boolean doAngle = doAngleRadioButton.isSelected();
        //启用(1)/禁用(0) 角度投票(整张图片以最大可能文字方向来识别)，当禁用文字方向检测时，此项也不起作用，默认关闭
        boolean mostAngle = mostAngleRadioButton.isSelected();
        try {
            new Thread(() -> {
                try {
                    runOcr(imageUrl, new ParamConfig(padding, maxSideLen, boxScore, boxThresh, unClipRatio, doAngle, mostAngle));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Platform.runLater(() -> {
                    sbButton.setText("识别");
                    sbButton.setDisable(false);
                });
            }).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void runOcr(String path, ParamConfig paramConfig) throws IOException {
        InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V3);
        OcrResult ocrResult = engine.runOcr(path, paramConfig);
        List<TextBlock> list = ocrResult.getTextBlocks();
        File file = new File(path);
        BufferedImage image = ImageIO.read(file);
        Graphics g = image.getGraphics();
        // 获取 Graphics 对象并强制转换为 Graphics2D 对象
        Graphics2D g2d = (Graphics2D) g;
        // 设置线条粗细为 2f
        g2d.setStroke(new BasicStroke(3f));
        g.setColor(Color.GREEN);//画笔颜色

        for (TextBlock textBlock : list) {
            //点位
            List<Point> pointlist = textBlock.getBoxPoint();
//            for (int i = 0; i < pointlist.size(); i++) {
//                int x = pointlist.get(i).getX();
//                int y = pointlist.get(i).getY();
//                int width = 1;
//                int height = 1;
//                g.drawRect(x, y, width, height);//矩形框(原点x坐标，原点y坐标，矩形的长，矩形的宽)
//            }
            int x = pointlist.get(0).getX();
            int y = pointlist.get(0).getY();
            int width = pointlist.get(2).getX() - x;
            int height = pointlist.get(2).getY() - y;
            g.drawRect(x, y, width, height);//矩形框(原点x坐标，原点y坐标，矩形的长，矩形的宽)

        }
        outData.setText(ocrResult.getStrRes().trim());
        FileOutputStream out1 = new FileOutputStream(desktopUrl + "temp.png");//输出图片的地址
        // 此处直接write会导致图片被压缩处理，失真
        ImageIO.write(image, "png", out1);
        imageOri.setImage(new Image(new FileInputStream(desktopUrl + "temp.png")));
        imageSizeSet();
    }

    public void chooseImage(ActionEvent actionEvent) throws FileNotFoundException {
        Stage stage = (Stage) chooseImageButton.getScene().getWindow();
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("图像文件", "*.png", "*.jpg", "*.jpeg"));
        fileChooser.setInitialDirectory(new File(System.getProperty("user.home")+"/Desktop"));
        File file = fileChooser.showOpenDialog(stage);
        if (file != null) {
            imageUrl = file.getPath();
            imageOri.setImage(new Image(new FileInputStream(file)));
            imageSizeSet();
        }
    }


    public void screenshot() {
        Stage primaryStage = (Stage) screenshotButton.getScene().getWindow();
        screenshot(primaryStage);
    }


    public void moren(ActionEvent actionEvent) {
        paddingTextField.setText("50");
        maxSideLenTextField.setText("0");
        boxScoreTextField.setText("0.5");
        boxThreshTextField.setText("0.3");
        unClipRatioTextField.setText("1.6");
        doAngleRadioButton.setSelected(false);
        mostAngleRadioButton.setSelected(false);
        paddingSlider.setValue(50);
        maxSideLenSlider.setValue(0);
        boxScoreThreshSlider.setValue(0.5);
        boxThreshSlider.setValue(0.3);
        unClipRatioSlider.setValue(1.6);
    }


//===================================== 分割线================================================

    /*
     * 图片滚轮方法缩小 拖动
     * */
    public void setImage() {
        Group group = new Group();
        imageScrollPane.setContent(group);
        group.getChildren().add(imageOri);
        //设置可以拖动
        imageScrollPane.setPannable(true);
        imageSizeSet();
        imageOri.setOnScroll(new EventHandler<ScrollEvent>() {
            @Override
            public void handle(ScrollEvent e) {
                if (e.getDeltaY() == 0) {
                    return;
                }
                double scaleFactor = (e.getDeltaY() > 0) ? 1.1 : 1 / 1.1;
                imageOri.setScaleX(imageOri.getScaleX() * scaleFactor);
                imageOri.setScaleY(imageOri.getScaleY() * scaleFactor);
            }
        });
    }

    /**
     * 截图
     */
    public void screenshot(Stage primaryStage) {
        show(primaryStage);
    }

    /**
     * 图片居大小适应
     */
    public void imageSizeSet() {
        imageCenter();
    }

    private void imageCenter() {
        double ratioX = imageScrollPane.getPrefWidth() / imageOri.getImage().getWidth();
        double ratioY = imageScrollPane.getPrefHeight() / imageOri.getImage().getHeight();
        double reducCoeff = 0;
        if (ratioX >= ratioY) {
            reducCoeff = ratioY;
        } else {
            reducCoeff = ratioX;
        }
        imageOri.setScaleX(reducCoeff);
        imageOri.setScaleY(reducCoeff);
    }

    private void show(final Stage primaryStage) {
        primaryStage.setIconified(true);
        AnchorPane anchorPane = new AnchorPane();
        anchorPane.setStyle("-fx-background-color: #ffffff22");
        Scene scene = new Scene(anchorPane);
        scene.setFill(javafx.scene.paint.Paint.valueOf("#ffffff00"));
        final Stage stage = new Stage();
        stage.initStyle(StageStyle.TRANSPARENT);
        stage.setScene(scene);
        stage.setFullScreen(true);
        stage.setFullScreenExitHint("");
        stage.show();
        drag(anchorPane, stage);
        scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
            public void handle(KeyEvent event) {
                if (event.getCode() == KeyCode.ESCAPE) {
                    System.out.println("esc");
                    stage.close();
                    primaryStage.setIconified(false);
                }
            }
        });
    }

    private HBox hBox;
    private double screenStartX;
    private double screenStartY;
    private double screenEndX;
    private double screenEndY;

    private void drag(final AnchorPane anchorPane, final Stage primaryStage) {
        anchorPane.setOnMousePressed(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event) {
                anchorPane.getChildren().clear();
                hBox = new HBox();
                hBox.setBackground(null);
                hBox.setBorder(new Border(new BorderStroke(
                        javafx.scene.paint.Paint.valueOf("#Cd3700"),
                        BorderStrokeStyle.SOLID
                        , null
                        , new BorderWidths(2)
                )));
                screenStartX = event.getScreenX();
                screenStartY = event.getScreenY();
                anchorPane.getChildren().add(hBox);
                AnchorPane.setLeftAnchor(hBox, screenStartX);
                AnchorPane.setTopAnchor(hBox, screenStartY);
            }
        });
        anchorPane.setOnDragDetected(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent event) {
                anchorPane.startFullDrag();
            }
        });
        anchorPane.setOnMouseDragOver(new EventHandler<MouseDragEvent>() {
            public void handle(MouseDragEvent event) {
                Label label = new Label();
                label.setAlignment(Pos.CENTER);
                label.setPrefWidth(120);
                label.setPrefHeight(30);
                label.setTextFill(javafx.scene.paint.Paint.valueOf("#ffffff"));
                label.setStyle("-fx-background-color: #000000");
                AnchorPane.setLeftAnchor(label, screenStartX);
                AnchorPane.setTopAnchor(label, screenStartY - 30);
                anchorPane.getChildren().add(label);
                double screenX = event.getScreenX();
                double screenY = event.getScreenY();
                double width = screenX - screenStartX;
                double height = screenY - screenStartY;
                hBox.setPrefWidth(width);
                hBox.setPrefHeight(height);
                label.setText((int) width + "x" + (int) height);
            }
        });
        anchorPane.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
            public void handle(MouseDragEvent event) {
                Stage stage = (Stage) OcrApplication.view1.screenshotButton.getScene().getWindow();
                screenEndX = event.getScreenX();
                screenEndY = event.getScreenY();
                Button button = new Button("确定");
                Button button2 = new Button("取消");
                button.setFont(new Font(10));
                button2.setFont(new Font(10));
                hBox.getChildren().add(button);
                hBox.getChildren().add(button2);
                hBox.setAlignment(Pos.BOTTOM_RIGHT);
                button.setOnAction(new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent event) {
                        getScreenImg(primaryStage);
                        stage.setIconified(false);
                    }
                });
                button2.setOnAction(new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent event) {
                        primaryStage.close();
                        stage.setIconified(false);
                    }
                });
            }
        });
    }

    private void getScreenImg(Stage primaryStage) {
        ImageView imageOri = OcrApplication.view1.imageOri;
        primaryStage.close();
        double w = screenEndX - screenStartX;
        double h = screenEndY - screenStartY;
        try {
            Robot robot = new Robot();
            java.awt.Rectangle rectangle = new java.awt.Rectangle((int) screenStartX, (int) screenStartY, (int) w, (int) h);
            BufferedImage screenCapture = robot.createScreenCapture(rectangle);
            // 保存截图到文件（可选）
            ImageIO.write(screenCapture, "png", new File(desktopUrl + "temp.png"));
            // 将BufferedImage转换为JavaFX可用的图像
            WritableImage writableImage = new WritableImage(screenCapture.getWidth(), screenCapture.getHeight());
            pixelFormatConverter(screenCapture, writableImage);
            imageUrl = desktopUrl + "temp.png";
            imageOri.setImage(writableImage);
            imageSizeSet();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void pixelFormatConverter(BufferedImage bufferedImage, WritableImage writableImage) {
        for (int y = 0; y < bufferedImage.getHeight(); y++) {
            for (int x = 0; x < bufferedImage.getWidth(); x++) {
                int pixel = bufferedImage.getRGB(x, y);
                writableImage.getPixelWriter().setArgb(x, y, pixel);
            }
        }
    }
}